package com.zatech.cgnci.project.base.aspect;

import com.zatech.cgnci.project.base.annotation.IgnoreTriggerLog;
import com.zatech.cgnci.project.base.utils.FastJsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.CodeSignature;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author history
 */
@Slf4j
@Aspect
@Component
public class HttpRequestAspect {

    public HttpRequestAspect() {
    }

    @Pointcut("(@within(org.springframework.web.bind.annotation.RestController) " +
            "|| @within(org.springframework.stereotype.Controller)) " +
            "&& (@annotation(org.springframework.web.bind.annotation.GetMapping)" +
            "|| @annotation(org.springframework.web.bind.annotation.PostMapping)" +
            "|| @annotation(org.springframework.web.bind.annotation.PutMapping)" +
            "|| @annotation(org.springframework.web.bind.annotation.DeleteMapping)" +
            "|| @annotation(org.springframework.web.bind.annotation.RequestMapping))")
    public void aspect() {
    }

    @Before(value = "aspect()")
    public void beforMethod(JoinPoint joinPoint) {
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            if (isfilterUri(request))
                return;
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            String logStr = "【HTTP接口请求日志】\r\n";
            logStr += "[REQUEST URI]: " + request.getRequestURI() + "\r\n";
            logStr += "[HTTP METHOD]: " + request.getMethod() + "\r\n";
            logStr += "[CLASS METHOD]: " + signature.getMethod().toString() + "\r\n";
            logStr += "[REQUEST PARAMETERS]: ";
            String[] params = ((CodeSignature) joinPoint.getStaticPart().getSignature()).getParameterNames();
            Object[] args = joinPoint.getArgs();
            for (int i = 0; i < args.length; i++) {
                if (args[i] instanceof HttpServletRequest || args[i] instanceof HttpServletResponse || args[i] instanceof MultipartFile || args[i] instanceof MultipartFile[]) {
                    continue;
                }
                if (args[i] == null || isPrimitive(args[i].getClass()) || args[i] instanceof String || args[i] instanceof MultipartFile) {
                    logStr += params[i] + " = " + args[i] + (i == args.length - 1 ? "" : " & ");
                } else {
                    logStr += params[i] + " = " + FastJsonUtils.toJSONString(args[i]) + (i == args.length - 1 ? "" : " & ");
                }
            }
            IgnoreTriggerLog ignoreTriggerLog = signature.getMethod().getAnnotation(IgnoreTriggerLog.class);
            if (ignoreTriggerLog == null) {
                log.debug(logStr);
            }
        } catch (Throwable e) {
            log.error("HttpRequestAspect Error", e);
        }
    }


    @AfterReturning(value = "aspect()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        if (isfilterUri(request))
            return;
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        StringBuilder logStr = new StringBuilder();
        logStr.append("【HTTP接口响应日志】\r\n");
        logStr.append("[REQUEST URI]: " + request.getRequestURI() + "\r\n");
        logStr.append("[HTTP METHOD]: " + request.getMethod() + "\r\n");
        logStr.append("[CLASS METHOD]: " + signature.getMethod().toString() + "\r\n");
        logStr.append("[RESPONSE DATA]: " + FastJsonUtils.toJSONString(result));
        IgnoreTriggerLog ignoreTriggerLog = signature.getMethod().getAnnotation(IgnoreTriggerLog.class);
        if (ignoreTriggerLog == null) {
            log.debug(logStr.toString());
        }
    }


    public static boolean isfilterUri(HttpServletRequest request) {
        String requestUri = request.getRequestURI();
        if (StringUtils.isNotBlank(requestUri)) {
            return requestUri.equals("/cgnci/error") || requestUri.startsWith("/cgnci/swagger")
                    || requestUri.startsWith("/cgnci/api/area/getAll")
                    || requestUri.startsWith("/cgnci/v2/api-docs")
                    || requestUri.startsWith("/cgnci/swagger-resources");
        }
        return false;
    }


    private boolean isPrimitive(Class<?> clazz) {
        try {
            if (clazz.isPrimitive()) {
                return true;
            }
            return ((Class<?>) clazz.getField("TYPE").get(null)).isPrimitive();
        } catch (Exception e) {
            return false;
        }
    }

}
